前言:
- 多线程;
- 多进程;
- 进程、线程对比;
- 多协程;
- 进程、线程、协程对比。
Python 多任务-线程、进程与协程
什么叫“多任务”呢?简单地说,就是操作系统可以同时运行多个任务。
一、线程
线程是进程的一个实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。
并行/并发
并发
指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已)
并行
指的是任务数小于等于cpu核数,即任务真的是一起执行的
多线程图解
共享全局变量与问题
在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据。
问题:
如果多个线程同时对同一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确。(即线程非安全)
同步/异步
同步:单线程(从上到下依次执行顺序)
异步:多线程(开启多个任务一同执行,互不影响)
互斥锁
当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制。
锁的好处:
- 确保了某段关键代码只能由一个线程从头到尾完整地执行
锁的坏处:
- 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁
死锁(一种 bug)
在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。
避免死锁
- 程序设计时要尽量避免(银行家算法)
- 添加超时时间等
案例
1.多线程体验
# Python 解释器中有一个模块专门控制线程,实现多任务 |
2.自定义线程类
import threading |
二、进程
运行的程序以及运行时用到的资源这个整体称之为进程,是系统进行资源分配和调度的一个独立单位。
进程间通信-Queue
进程间通信:运行的程序之间的数据共享。
三、进程、线程对比
功能
- 进程,能够完成多任务,比如 在一台电脑上能够同时运行多个 QQ。
- 线程,能够完成多任务,比如 一个 QQ 中的多个聊天窗口。
定义的不同
- 进程是系统进行资源分配和调度的一个独立单位。
- 线程是进程的一个实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。
- 线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
区别
- 一个程序至少有一个进程,一个进程至少有一个线程。
- 线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
- 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率,
- 线线程不能够独立执行,必须依存在进程中。
- 可以将进程理解为工厂中的一条流水线,而其中的线程就是这个流水线上的工人。
优缺点
- 线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。
四、协程
协程,又称微线程,纤程。英文名Coroutine。
greenlet
为了更好使用协程来完成多任务,python中的greenlet模块对其封装,从而使得切换任务变的更加简单
安装方式
使用如下命令安装 greenlet 模块:
pip3 list: 验证已安装的python第三方插件(如果没有pip3会提示安装) |
gevent
greenlet已经实现了协程,但是这个还的人工切换,是不是觉得太麻烦了,不要捉急,python还有一个比greenlet更强大的并且能够自动切换任务的模块gevent
其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。
由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO
安装方式
pip3 install gevent |
协程和线程差异
在实现多任务时, 线程切换从系统层面远不止保存和恢复 CPU 上下文这么简单。
操作系统为了程序运行的高效性每个线程都有自己缓存 Cache 等等数据,操作系统还会帮你做这些数据的恢复操作。所以线程的切换非常耗性能。
但是协程的切换只是单纯的操作 CPU 的上下文,所以一秒钟切换个上百万次系统都抗的住。
五、进程、线程、协程对比
- 进程是资源分配的单位
- 线程是操作系统调度的单位
- 进程切换需要的资源很最大,效率很低
- 线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
- 协程切换任务资源很小,效率高
- 多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发